# 指定文件编码为UTF-8
# coding: utf-8

"""
misclassified_mnist.py 功能说明：
1. 可视化深度卷积神经网络在MNIST数据集上的错误分类样本
2. 加载预训练的DeepConvNet模型
3. 计算模型在测试集上的准确率
4. 展示前20个分类错误的样本图像及其标签
5. 帮助分析模型在哪些数字上容易出错

关键点：
- 使用预训练的深度卷积网络模型
- 批量处理测试数据提高效率
- 可视化错误分类样本
- 显示样本的真实标签和预测结果
- 支持调整显示样本数量
"""

# 导入系统模块
import sys, os
# 添加父目录到系统路径
sys.path.append(os.pardir)
# 导入NumPy数值计算库
import numpy as np
# 导入matplotlib绘图库
import matplotlib.pyplot as plt
# 从deep_convnet导入深度卷积网络类
from deep_convnet import DeepConvNet
# 从dataset.mnist导入MNIST数据加载函数
from dataset.mnist import load_mnist

# 加载MNIST数据集(保持原始图像结构)
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)

# 初始化深度卷积网络
network = DeepConvNet()
# 加载预训练参数
network.load_params("deep_convnet_params.pkl")

print("calculating test accuracy ... ")
# 如需快速测试，可减少数据量(取消注释以下三行)
#sampled = 1000
#x_test = x_test[:sampled]
#t_test = t_test[:sampled]

# 初始化分类结果存储
classified_ids = []

# 计算测试准确率
acc = 0.0
batch_size = 100  # 批量大小

# 分批处理测试数据
for i in range(int(x_test.shape[0] / batch_size)):
    tx = x_test[i*batch_size:(i+1)*batch_size]  # 当前批输入
    tt = t_test[i*batch_size:(i+1)*batch_size]  # 当前批标签
    y = network.predict(tx, train_flg=False)    # 预测(测试模式)
    y = np.argmax(y, axis=1)                   # 获取预测类别
    classified_ids.append(y)                    # 存储预测结果
    acc += np.sum(y == tt)                     # 累计正确数

# 计算总体准确率
acc = acc / x_test.shape[0]
print("test accuracy:" + str(acc))

# 整理分类结果
classified_ids = np.array(classified_ids)
classified_ids = classified_ids.flatten()

# 可视化设置
max_view = 20      # 最多显示20个错误样本
current_view = 1    # 当前显示位置

# 创建图形窗口
fig = plt.figure()
# 调整子图间距
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.2, wspace=0.2)

# 存储错误分类样本信息
mis_pairs = {}

# 遍历所有测试样本
for i, val in enumerate(classified_ids == t_test):
    # 只处理分类错误的样本
    if not val:
        # 创建子图
        ax = fig.add_subplot(4, 5, current_view, xticks=[], yticks=[])
        # 显示错误分类的图像(28x28灰度图)
        ax.imshow(x_test[i].reshape(28, 28), cmap=plt.cm.gray_r, interpolation='nearest')
        # 记录真实标签和预测结果
        mis_pairs[current_view] = (t_test[i], classified_ids[i])

        current_view += 1
        # 达到最大显示数量时停止
        if current_view > max_view:
            break

# 打印错误分类结果
print("======= misclassified result =======")
print("{view index: (label, inference), ...}")
print(mis_pairs)

# 显示图形
plt.show()

"""
输出结果说明：
1. 测试准确率：显示模型整体分类性能
2. 错误分类样本：显示前20个分类错误的样本图像
3. 每个子图标注：(真实标签, 预测结果)

使用建议：
1. 可通过修改max_view调整显示样本数量
2. 分析错误样本可帮助改进模型
3. 常见错误类型：
   - 相似数字混淆(如7和9)
   - 书写不规范的样本
   - 图像质量较差的样本
"""
